package com.ctshk.rpc.user.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.*;
import com.ctshk.common.enums.appUser.UserCollectionTypeCode;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.rpc.hotel.service.IHotelH5Service;
import com.ctshk.rpc.localfun.service.ILocalFunAppProductService;
import com.ctshk.rpc.scenic.service.app.IScenicTicketEsSearchService;
import com.ctshk.rpc.season.service.ISeasonFixedProductPackageService;
import com.ctshk.rpc.tour.service.ISeriesTripAppService;
import com.ctshk.rpc.user.dto.UserCollectionHeadDTO;
import com.ctshk.rpc.user.dto.UserCollectionListDTO;
import com.ctshk.rpc.user.dto.UserFootPointListDTO;
import com.ctshk.rpc.user.entity.UserCollection;
import com.ctshk.rpc.user.entity.UserFootPoint;
import com.ctshk.rpc.user.mapper.UserCollectionMapper;
import com.ctshk.rpc.user.req.UserCollectionBatchCancelReq;
import com.ctshk.rpc.user.req.UserCollectionPageReq;
import com.ctshk.rpc.user.req.UserCollectionReq;
import com.ctshk.rpc.user.req.UserFootPointReq;
import com.ctshk.rpc.user.service.IUserCollectionService;
import com.ctshk.rpc.user.service.IUserFootPointService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.springframework.data.redis.core.RedisTemplate;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  用户收藏接口实现类
 * </p>
 *
 * @author 李新科
 * @date 2021/5/17 20:44
 */
@Slf4j
@DubboService
public class UserCollectionServiceImpl extends ServiceImpl<UserCollectionMapper, UserCollection> implements IUserCollectionService {

    @Autowired
    private UserCollectionMapper userCollectionMapper;

    @DubboReference
    private IUserFootPointService userFootPointService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;



    @Override
    public Result<PageResponse<UserCollectionListDTO>> queryPage(UserCollectionPageReq req) {
        Page<UserCollection> queryPage = new Page(req.getPageNo(), req.getPageSize());
        Page<UserCollection> page = userCollectionMapper.selectPage(queryPage, new QueryWrapper<UserCollection>()
                .lambda().eq(UserCollection::getUserId, req.getUserId())
                .eq(UserCollection::getIsDeleted, IsDeletedCode.NO.getCode())
                .groupBy(UserCollection::getDetailId)
        .eq(req.getType() != null, UserCollection::getType, req.getType()));

        List<UserCollectionListDTO> listDTOS = EntityUtil.copyList(page.getRecords(), UserCollectionListDTO.class);
        PageResponse<UserCollectionListDTO> result = new PageResponse<>(listDTOS,
                page.getCurrent() == 1, page.getTotal() <= (page.getCurrent() *
                page.getSize()), page.getTotal(), page.getCurrent(), page.getSize());
        return Result.success(result);
    }

    @Override
    public Result<List<Object>> add(UserCollectionReq req) {
       Object o = redisTemplate.opsForHash().get(RedisConstants.FOOT_POINT_USER_ID + req.getUserId(), req.getDetailId().toString());
        if(o != null) {
            UserFootPoint userFootPoint = (UserFootPoint) o;
            req = EntityUtil.copy(userFootPoint, UserCollectionReq.class);
        } else {
            UserFootPointReq userFootPointReq = new UserFootPointReq();
            userFootPointReq.setUserId(req.getUserId());
            userFootPointReq.setDetailId(req.getDetailId());
            Result<UserFootPointListDTO> result = userFootPointService.detail(userFootPointReq);
            if(result.isSuccess() && result.getData() != null) {
                UserFootPointListDTO details = result.getData();
                req = EntityUtil.copy(details, UserCollectionReq.class);
            } else {
                throw new BusinessException(SystemError.SYS_433,"收藏失败");
            }
        }

        Integer count = userCollectionMapper.selectCount(Wrappers.<UserCollection>lambdaQuery()
                .eq(UserCollection::getDetailId, req.getDetailId())
                .eq(UserCollection::getUserId, req.getUserId())
        .eq(UserCollection::getIsDeleted, IsDeletedCode.NO.getCode()));

        if(count == 0) {
            long id = SnowflakeIdWorker.nextId();
            LocalDateTime now = LocalDateTime.now();
            Long userId = req.getUserId();
            UserCollection entity = EntityUtil.copy(req, UserCollection.class);
            entity.setId(id);
            entity.setUserId(userId);
            entity.setCreateId(userId);
            entity.setCurrencyId(Currency.HKD.getCode());
            entity.setCurrency(Currency.HKD.getCurrency());
            entity.setGmtCreate(now);
            entity.setGmtModified(now);
            entity.setIsDeleted(IsDeletedCode.NO.getCode());
            userCollectionMapper.insert(entity);
        }

        List<Object> objects = userCollectionMapper.selectObjs(Wrappers.<UserCollection>lambdaQuery()
                .select(UserCollection::getDetailId)
                .eq(UserCollection::getUserId, req.getUserId())
                .eq(UserCollection::getIsDeleted, IsDeletedCode.NO.getCode())
                .groupBy(UserCollection::getDetailId));
        return Result.success(objects);
    }

    @Override
    public Result<List<Object>> delete(Long detailsId, Long userId) {
        userCollectionMapper.delete(new QueryWrapper<UserCollection>()
                .lambda().eq(UserCollection::getDetailId, detailsId)
                .eq(UserCollection::getCreateId, userId));
        List<Object> objects = userCollectionMapper.selectObjs(Wrappers.<UserCollection>lambdaQuery()
                .select(UserCollection::getDetailId)
                .eq(UserCollection::getUserId, userId)
                .eq(UserCollection::getIsDeleted, IsDeletedCode.NO.getCode())
                .groupBy(UserCollection::getDetailId));
        return Result.success(objects);
    }

    @Override
    public Result batchDelete(UserCollectionBatchCancelReq req) {
        userCollectionMapper.delete(new QueryWrapper<UserCollection>()
                .lambda().in(UserCollection::getDetailId, req.getIds())
                .eq(UserCollection::getCreateId, req.getUserId()));
        return Result.success();
    }

    @Override
    public Result<UserCollectionHeadDTO> queryHead(Long userId) {
        List<Map<String, Object>> list = userCollectionMapper.selectMaps(new QueryWrapper<UserCollection>()
        .select("type,count(distinct detail_id) as num").lambda()
                .eq(UserCollection::getUserId, userId)
        .eq(UserCollection::getIsDeleted, IsDeletedCode.NO.getCode())
                .groupBy(UserCollection::getType));
        UserCollectionHeadDTO userCollectionHeadDTO = new UserCollectionHeadDTO();
        if(CollectionUtils.isNotEmpty(list)) {
            Class<? extends UserCollectionHeadDTO> aClass = userCollectionHeadDTO.getClass();
            for (Map<String, Object> map : list) {
                Integer type = (Integer) map.get("type");
                Integer num = ((Long) map.get("num")).intValue();
                UserCollectionTypeCode userCollectionTypeCode = UserCollectionTypeCode.get(type);
                if(userCollectionTypeCode != null) {
                    String name = userCollectionTypeCode.name().toLowerCase();
                    String fieldName = (name.contains("_")? StrUtil.toCamelCase(name):name) + "Num";
                    try {
                        Field field = aClass.getDeclaredField(fieldName);
                        PropertyDescriptor descriptor = new PropertyDescriptor(field.getName(), aClass);
                        Method writeMethod = descriptor.getWriteMethod();
                        writeMethod.invoke(userCollectionHeadDTO, num);
                    } catch (Exception e) {
                        log.error("该字段反射set方法异常： " + fieldName,e);
                    }
                }
            }
        }

        return Result.success(userCollectionHeadDTO);
    }

    @Override
    public Integer countByUserId(Long userId) {
        Integer count = baseMapper.selectCount(new QueryWrapper<UserCollection>()
                .select("DISTINCT DETAIL_ID").lambda()
                .eq(UserCollection::getUserId, userId)
                .eq(UserCollection::getIsDeleted, IsDeletedCode.NO.getCode()));
        return count == null?0:count;
    }

    @Override
    public Result<Boolean> isCollect(Long productId, Long userId) {
        return Result.success(baseMapper.selectCount(Wrappers.<UserCollection>lambdaQuery()
                .eq(UserCollection::getUserId, userId)
                .eq(UserCollection::getDetailId, productId)
                .eq(UserCollection::getIsDeleted, IsDeletedCode.NO.getCode())) > 0);
    }

    @Override
    public Result<List<Object>> collectedlist(Long userId) {
        List<Object> objects = userCollectionMapper.selectObjs(Wrappers.<UserCollection>lambdaQuery()
                .select(UserCollection::getDetailId)
                .eq(UserCollection::getUserId, userId)
                .eq(UserCollection::getIsDeleted, IsDeletedCode.NO.getCode())
                .groupBy(UserCollection::getDetailId));
        return Result.success(objects);
    }
}
